using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;

namespace HEFramework
{
    /// <summary>
    /// UI层
    /// </summary>
    public enum eUILayer
    {
        Bottom, //底层
        Middle, //中层
        Top, //上层
        Pop, //气泡层
        Max,
    }

    /// <summary>
    /// UI配置信息
    /// </summary>
    public struct UIConfigInfo
    {
        public eUILayer layer;
        public int sortingOrder;
    }


    /// <summary>
    ///
    /// UI加载器
    /// 
    /// ----------------------------------------
    /// 作者：pan
    /// 创建时间：2022-05-16 17:40:37
    /// ----------------------------------------
    /// </summary>
    public class UILoader : Singleton<UILoader>, ISingletonAwake
    {
        /// <summary>
        /// UI字典
        /// </summary>
        private Dictionary<string, IUIWindowBehaviour> uis = new();

        /// <summary>
        ///备用的UI缓存字典
        /// </summary>   
        private Dictionary<string, IUIWindowBehaviour> uiCaches = new();

        /// <summary>
        /// UI加载字典
        /// </summary>
        private List<string> uiLoadings = new();

        /// <summary>
        /// UI层级字典
        /// </summary>
        private Dictionary<eUILayer, int> uiLayers = new();

        /// <summary>
        /// UI根节点
        /// </summary>
        private GameObject uiRoot;

        /// <summary>
        /// UI配置信息字典
        /// </summary>
        private Dictionary<string, UIConfigInfo> uiConfigs;

        /// <summary>
        /// UI相机
        /// </summary>
        private Camera uiCamera;


        /// <summary>
        /// 资源
        /// </summary>
        private Assets assets;


        #region 周期

        /// <summary>
        /// 初始化
        /// </summary>
        public void Awake()
        {
            //生成UI根节点
            uiRoot = GameObject.Find("UI");
            //生成不同层队列
            for (int i = 0; i < (int)eUILayer.Max; i++)
            {
                eUILayer layer = (eUILayer)i;
                GameObject gameObject = new GameObject();
                gameObject.name = ((eUILayer)i).ToString();
                gameObject.transform.SetParent(uiRoot.transform);
                gameObject.transform.localPosition = Vector3.zero;
                uiLayers.Add(layer, i * 10000);
            }

            //获取配置信息
            uiConfigs = GetUIConfig();
            //获取相机信息
            uiCamera = GetUICamera();
            assets = AssetLoader.Instance.GetAssets();
        }


        /// <summary>
        /// 销毁
        /// </summary>
        protected override void Destroy()
        {
            //清理根节点
            for (int i = 0; i < uiRoot.transform.childCount; i++)
            {
                Transform t = uiRoot.transform.GetChild(i);
                GameObject.Destroy(t.gameObject);
            }

            assets.Dispose();
        }

        #endregion


        /// <summary>
        /// 弹出UI（同步）
        /// </summary>
        /// <param name="_flag"></param>
        /// <returns></returns>
        public IUIWindowBehaviour PushUISyn(string _flag)
        {
            IUIWindowBehaviour uiWindowBehaviour;

            //检测正在展示的UI中是否存在这个UI
            uiWindowBehaviour = GetShowUI(_flag);
            if (uiWindowBehaviour != null)
            {
                uiWindowBehaviour.Show();
                return uiWindowBehaviour;
            }

            //检测缓存的UI中是否存在这个UI
            uiWindowBehaviour = GetCacheUI(_flag);
            if (uiWindowBehaviour != null)
            {
                uiWindowBehaviour.Show();
                uiCaches.Remove(_flag);
                uis.Add(_flag, uiWindowBehaviour);
                return uiWindowBehaviour;
            }

            //已在加载中,不处理
            if (uiLoadings.Contains(_flag))
            {
                return null;
            }

            uiLoadings.Add(_flag);
            //未存在过
            string uiName = _flag + UISettingScriptableObject.Instance.UIPrefabExtension;
            GameObject obj = LoadUISyn(uiName);
            UIConfigInfo info;
            uiConfigs.TryGetValue(_flag, out info);
            GameObject gameObject = obj;
            gameObject.transform.SetParent(GetUILayer(info.layer).transform, false);
            gameObject.transform.position = Vector3.zero;
            uiWindowBehaviour = gameObject.GetComponent<IUIWindowBehaviour>();
            if (uiWindowBehaviour == null)
            {
                uiWindowBehaviour = gameObject.AddComponent<UIWindowBehaviour>();
            }

            uiWindowBehaviour.Awake();
            IUICanvasBehaviour uiCanvasBehaviour = uiWindowBehaviour.GetCanvas();
            uiWindowBehaviour.SetFlag(_flag);
            uiCanvasBehaviour.SetOrder(uiLayers[info.layer] + info.sortingOrder).SetCamera(uiCamera);
            uiWindowBehaviour.Show();
            uis.Add(_flag, uiWindowBehaviour);
            uiLoadings.Remove(_flag);
            return uiWindowBehaviour;
        }


        /// <summary>
        ///  弹出UI（异步）
        /// </summary>
        /// <param name="_flag"></param>
        /// <param name="_callback"></param>
        public void PushUIAsync(string _flag, Action<IUIWindowBehaviour> _callback)
        {
            IUIWindowBehaviour uiWindowBehaviour;
            //检测正在展示的UI中是否存在这个UI
            uiWindowBehaviour = GetShowUI(_flag);
            if (uiWindowBehaviour != null)
            {
                uiWindowBehaviour.Show();
                _callback(uiWindowBehaviour);
                return;
            }

            //检测缓存的UI中是否存在这个UI
            uiWindowBehaviour = GetCacheUI(_flag);
            if (uiWindowBehaviour != null)
            {
                uiWindowBehaviour.Show();
                uiCaches.Remove(_flag);
                uis.Add(_flag, uiWindowBehaviour);
                _callback(uiWindowBehaviour);
                return;
            }

            //已在加载中,不处理
            if (uiLoadings.Contains(_flag))
            {
                return;
            }

            uiLoadings.Add(_flag);

            //未存在过
            string uiName = _flag + UISettingScriptableObject.Instance.UIPrefabExtension;
            LoadUIAsync(uiName, _ =>
            {
                UIConfigInfo info;
                uiConfigs.TryGetValue(_flag, out info);
                GameObject gameObject = _;
                gameObject.transform.SetParent(GetUILayer(info.layer).transform, false);
                gameObject.transform.position = Vector3.zero;
                uiWindowBehaviour = gameObject.GetComponent<IUIWindowBehaviour>();
                if (uiWindowBehaviour == null)
                {
                    uiWindowBehaviour = gameObject.AddComponent<UIWindowBehaviour>();
                }

                uiWindowBehaviour.Awake();
                IUICanvasBehaviour uiCanvasBehaviour = uiWindowBehaviour.GetCanvas();
                uiWindowBehaviour.SetFlag(_flag);
                uiCanvasBehaviour.SetOrder(uiLayers[info.layer] + info.sortingOrder).SetCamera(uiCamera);
                uiWindowBehaviour.Show();
                uis.Add(_flag, uiWindowBehaviour);
                uiLoadings.Remove(_flag);

                _callback(uiWindowBehaviour);
            });
        }


        /// <summary>
        /// 弹回UI
        /// </summary>
        /// <param name="_behaviour"></param>
        public void PopUI(IUIWindowBehaviour _behaviour)
        {
            IUIWindowBehaviour uiWindowBehaviour;
            if (uis.TryGetValue(_behaviour.Flag, out uiWindowBehaviour))
            {
                uiWindowBehaviour.Hide();
                uis.Remove(_behaviour.Flag);
                uiCaches.Add(_behaviour.Flag, _behaviour);
            }
        }


        /// <summary>
        /// 销毁某个UI
        /// </summary>
        /// <param name="_behaviour"></param>
        public void DestroyUI(IUIWindowBehaviour _behaviour)
        {
            IUIWindowBehaviour uiWindowBehaviour;
            if (uis.TryGetValue(_behaviour.Flag, out uiWindowBehaviour))
            {
                uis.Remove(_behaviour.Flag);
                uiWindowBehaviour.Destroy();
            }
            else if (uiCaches.TryGetValue(_behaviour.Flag, out uiWindowBehaviour))
            {
                uiCaches.Remove(_behaviour.Flag);
                uiWindowBehaviour.Destroy();
            }
        }

        /// <summary>
        /// 清除缓存的UI
        /// </summary>
        public void DestroyCacheUI()
        {
            foreach (var ui in uiCaches.Values)
            {
                ui.Destroy();
            }

            uiCaches.Clear();
        }

        /// <summary>
        /// 所有UI变成缓存
        /// </summary>
        public void AllUIToCache()
        {
            foreach (var key in uis.Keys)
            {
                IUIWindowBehaviour uiWindowBehaviour;
                uiWindowBehaviour = uis[key];
                uiWindowBehaviour.Hide();
                //如果缓存中没有
                if (!uiCaches.TryGetValue(uiWindowBehaviour.Flag, out uiWindowBehaviour))
                {
                    uiCaches.Add(key, uiWindowBehaviour);
                }
            }

            uis.Clear();
        }


        /// <summary>
        /// 展示所有UI
        /// </summary>
        public void ShowAllUI()
        {
            foreach (var item in uis.Values)
            {
                item.Show();
            }
        }

        /// <summary>
        /// 隐藏所有UI
        /// </summary>
        public void HideAllUI()
        {
            foreach (var item in uis.Values)
            {
                item.Hide();
            }
        }


        /// <summary>
        /// 获取层级
        /// </summary>
        /// <returns></returns>
        private Transform GetUILayer(eUILayer _layer)
        {
            Transform transform = uiRoot.transform.GetChild((int)_layer);
            return transform;
        }


        /// <summary>
        /// 获取缓存UI
        /// </summary>
        /// <param name="_flag"></param>
        /// <returns></returns>
        private IUIWindowBehaviour GetCacheUI(string _flag)
        {
            IUIWindowBehaviour uiWindowBehaviour;
            if (uiCaches.TryGetValue(_flag, out uiWindowBehaviour))
            {
                return uiWindowBehaviour;
            }

            return null;
        }

        /// <summary>
        /// 获取展示UI
        /// </summary>
        /// <param name="_flag"></param>
        /// <returns></returns>
        private IUIWindowBehaviour GetShowUI(string _flag)
        {
            IUIWindowBehaviour uiWindowBehaviour;
            if (uis.TryGetValue(_flag, out uiWindowBehaviour))
            {
                return uiWindowBehaviour;
            }

            return null;
        }


        #region 核心加载方法

        /// <summary>
        /// 加载UI（同步）
        /// </summary>
        /// <param name="_uiName"></param>
        /// <returns></returns>
        private GameObject LoadUISyn(string _uiName)
        {
            string assetBundleName = UISettingScriptableObject.Instance.UIPrefabBuildPath.Replace("Assets/AssetBundles/", "").Replace("Assets/Resources/", "");
            string assetName = _uiName;
            GameObject gameObject = assets.LoadAssetSyn<GameObject>(assetBundleName, assetName, ResourceConfig.Extension.PREFAB);
            gameObject = GameObject.Instantiate(gameObject);
            return gameObject;
        }

        /// <summary>
        /// 加载UI（异步）
        /// </summary>
        /// <param name="_uiName"></param>
        /// <returns></returns>
        private void LoadUIAsync(string _uiName, Action<GameObject> _callback)
        {
            string assetBundleName = UISettingScriptableObject.Instance.UIPrefabBuildPath.Replace("Assets/AssetBundles/", "").Replace("Assets/Resources/", "");
            string assetName = _uiName;
            assets.LoadAssetAsync<GameObject>(assetBundleName, assetName, ResourceConfig.Extension.PREFAB, _ =>
            {
                GameObject gameObject = GameObject.Instantiate(_);
                _callback.Invoke(gameObject);
            });
        }

        /// <summary>
        /// 获取UI配置数据
        /// </summary>
        /// <returns></returns>
        private Dictionary<string, UIConfigInfo> GetUIConfig()
        {
            Assembly assembly = Assembly.Load("Assembly-CSharp"); //程序集名称
            var type = assembly.GetType("HEFramework.UIConfig"); //程序集名称.类名
            if (type == null)
            {
                Debug.LogError("Please create [UIConfig].");
                return null;
            }

            object obj = Activator.CreateInstance(type);
            var dic = type.GetField("uiConfigs").GetValue(obj) as Dictionary<string, UIConfigInfo>;
            return dic;
        }

        /// <summary>
        /// 获取UI摄像机
        /// </summary>
        private Camera GetUICamera()
        {
            GameObject obj = GameObject.Find("UICamera");
            if (obj == null)
            {
                Debug.LogError("Not have [UICamera] in scene");
                return null;
            }

            Camera camera = obj.GetComponent<Camera>();
            if (camera == null)
            {
                Debug.LogError("Not have [UICamera] in scene");
                return null;
            }

            return camera;
        }

        #endregion
    }
}